﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace LocationAwareness
{
    public delegate void DelegatePanelUpdated();

    public partial class PoiPanel : UserControl
    {
        private ServiceHandler serviceHandler;
        private GUI gui;
        private Dictionary<string, bool> dictFilter;

        private delegate void ClearPanelPoi();
        private delegate void AddPoiView(IEnumerable<POI> pois);
        private delegate void AddPoiDetailPanel(PoiDetail detail);

        public event DelegatePanelUpdated PanelUpdated;

        private PoiDetailPanel poiDetailPanel;

        /// <summary>
        /// Creates a PoiPanel
        /// </summary>
        /// <param name="g">
        /// Instance of parent control
        /// </param>
        public PoiPanel(GUI g)
        {
            InitializeComponent();

            serviceHandler = new ServiceHandler();
            serviceHandler.PoisUpdated += new DelegatePoisUpdated(serviceHandler_poisUpdated);
            serviceHandler.DetailInfoGot += new DelegateDetailInfoGot(serviceHandler_DetailInfoGot);
            serviceHandler.DefaultImageGot += new DelegateDefaultImageGot(serviceHandler_DefaultImageGot);
            serviceHandler.DetailUpdated += new DelegateDetailUpdated(serviceHandler_DetailUpdated);
            serviceHandler.utzel += new UTzel(serviceHandler_utzel);

            gui = g;

            dictFilter = new Dictionary<string, bool>();

            catBoxCinema.Name = "cinema";
            catBoxCinema.TextOnPicture = LocawaToken.TkCinema;
            catBoxCulture.Name = "culture";
            catBoxCulture.TextOnPicture = LocawaToken.TkCulture;
            catBoxFastFood.Name = "fastfood";
            catBoxFastFood.TextOnPicture = LocawaToken.TkFastFood;
            catBoxBar.Name = "bar";
            catBoxBar.TextOnPicture = LocawaToken.TkBar;
            catBoxClub.Name = "club";
            catBoxClub.TextOnPicture = LocawaToken.TkClub;
            catBoxLocalTraffic.Name = "traffic";
            catBoxLocalTraffic.TextOnPicture = LocawaToken.TkTraffic;
            catBoxRestaurant.Name = "rest";
            catBoxRestaurant.TextOnPicture = LocawaToken.TkRestaurant;
            catBoxSupermarket.Name = "supermarket";
            catBoxSupermarket.TextOnPicture = LocawaToken.TkSupermarket;
            catBoxOther.Name = "misc";
            catBoxOther.TextOnPicture = LocawaToken.TkMisc;
        }

        void serviceHandler_utzel(string text)
        {
            label1.Text = text;
        }

        public bool ShowButtons
        {
            set
            {
                panelFilter.Visible = value;
            }
        }

        /// <summary>
        /// URL of the Server providing LocAwa
        /// </summary>
        public string ServiceUrl
        {
            set
            {
                serviceHandler.ServiceUrl = value;   
            }

            get
            {
                return serviceHandler.ServiceUrl;
            }
        }

        /// <summary>
        /// Specifies the file on the webserver the application connects to for the detail view.
        /// The string has to contain the substrings "{0}", "{1}" and "{2}".
        /// "{0}" will be replaced by the actual value of gps latitude.
        /// "{1}" will be replaced by the actual value of gps longtitude.
        /// "{2}" will be replaced by the value of the ID from the object, wich will be shown. 
        /// </summary>
        public string DetailFile
        {
            set
            {
                serviceHandler.DetailFile = value;
            }

            get
            {
                return serviceHandler.DetailFile;
            }
        }

        /// <summary>
        /// Specifies the file on the webserver the application connects to for the detail view.
        /// The string has to contain the substrings "{0}", "{1}" and "{2}".
        /// "{0}" will be replaced by the actual value of gps latitude.
        /// "{1}" will be replaced by the actual value of gps longtitude.
        /// "{2}" will be replaced by the value of the ID from the object, wich will be shown. 
        /// </summary>
        public string UpdateDetailFile
        {
            set
            {
                serviceHandler.UpdateDetailFile = value;
            }

            get
            {
                return serviceHandler.UpdateDetailFile;
            }
        }

        /// <summary>
        /// Specifies the file on the webserver the application connects to for the default view.
        /// The string has to contain the substrings "{0}" and "{1}".
        /// "{0}" will be replaced by the actual value of gps latitude.
        /// "{1}" will be replaced by the actual value of gps longtitude.
        /// </summary>
        public string DefaultFile
        {
            set
            {
                serviceHandler.DefaultFile = value;
            }

            get
            {
                return serviceHandler.DefaultFile;
            }
        }

        /// <summary>
        /// Method to update the contents of PoiPanel.
        /// </summary>
        public void UpdatePanel()
        {
            if (poiListPanel.Visible)
                serviceHandler.updatePois();
            else
                serviceHandler.updateDetail();
        }

        /// <summary>
        /// Event-method, occurs when the data for the default view are on the client.
        /// </summary>
        /// <param name="pois">
        /// List of instances of updated POIs. 
        /// </param>
        private void serviceHandler_poisUpdated(IEnumerable<POI> pois)
        {
            initPoiViews(pois);
            PanelUpdated();
        }

        /// <summary>
        /// Event-method, occurs when the data for the detail view are on the client.
        /// </summary>
        /// <param name="pois">
        /// Instance of the updated PoiDetail. 
        /// </param>
        void serviceHandler_DetailInfoGot(PoiDetail detailedPoi)
        {
            addPoiDetailPanel(detailedPoi);
            PanelUpdated();
        }

        /// <summary>
        /// Method for initializing the PoiPanel in default view with new POIs.
        /// </summary>
        /// <param name="pois">
        /// List of instances of updated POIs. 
        /// </param>
        private void initPoiViews(IEnumerable<POI> pois)
        {
            if (this.InvokeRequired)
                this.Invoke(new AddPoiView(initPoiViews), new object[] { pois });
            else
            {
                poiListPanel.BeginUpdate();
                foreach (POI poi in pois)
                {
                    PoiView poiView = new PoiView(poi);
                    poiView.Dock = DockStyle.Top;
                    poiView.Click += new EventHandler(poiView_Click);

                    if (!poiListPanel.AddPoiView(poiView))
                    {
                        serviceHandler.getDefaultImage(poi.ImagePath);
                    }
                }
                poiListPanel.EndUpdate();
            }
        }

        /// <summary>
        /// Method to intialize a PoiDetailPanel and add it to the PoiPanel.
        /// </summary>
        /// <param name="pois">
        /// Instance of the updated PoiDetail. 
        /// </param>
        private void addPoiDetailPanel(PoiDetail detail)
        {
            if (this.InvokeRequired)
                this.Invoke(new AddPoiDetailPanel(addPoiDetailPanel),new object[]{ detail });
            else
            {
                poiDetailPanel = new PoiDetailPanel(detail, serviceHandler.Latitude, 
                                                    serviceHandler.Longtitude);
                //poiDetailPanel.Dock = DockStyle.Fill;
                poiDetailPanel.Location = new Point(0, 24);
                poiDetailPanel.Size = new Size(240, 244);

                comboBoxChronic.AddPoi(detail);
                this.Controls.Add(poiDetailPanel);
            }
        }

        /// <summary>
        /// Method to update the shown PoiDetailPanel.
        /// </summary>
        /// <param name="pois">
        /// Instance of the updated PoiDetail. 
        /// </param>
        private void updatePoiDetailPanel(PoiDetail detail)
        {
            if (this.InvokeRequired)
                this.Invoke(new AddPoiDetailPanel(updatePoiDetailPanel), new object[] { detail });
            else
            {
                poiDetailPanel.updatePoiDetailPanel(detail, serviceHandler.Latitude, 
                                                    serviceHandler.Longtitude);
            }
        }

        /// <summary>
        /// Event-method, occurs when a PoiView representing a POI in default view is clicked.
        /// </summary>
        private void poiView_Click(object sender, EventArgs e)
        {
            gui.pauseTimer();
            poiListPanel.Visible = false;
            panelFilter.Visible = false;

            PoiView poiView = (PoiView)sender;
            PoiDetail poiDetail = comboBoxChronic.getPoiDetail(poiView.ObjectID);

            if(poiDetail != null)
            {
                addPoiDetailPanel(poiDetail);
                PanelUpdated();
            }
            else
            {
                PoiDetail p = new PoiDetail(poiView);
                serviceHandler.getDetailInfo(p);
            }
        }

        /// <summary>
        /// Event method for the clicked Quickfilter button.
        /// </summary>
        private void btnFilter_Click(object sender, EventArgs e)
        {
            CatBox clickedFilter = (CatBox)sender;
            if (clickedFilter.Pressed)
            {
                if (!dictFilter.ContainsKey(clickedFilter.Name))
                    dictFilter.Add(clickedFilter.Name, true);
                else
                    dictFilter[clickedFilter.Name] = true;

                serviceHandler.sendFilter(dictFilter);
            }
            else
            {
                dictFilter.Remove(clickedFilter.Name);
                serviceHandler.sendFilter(dictFilter);
            }
        }

        /// <summary>
        /// Method, called to show the default view, if detail view is displayed.
        /// </summary>
        public void ShowDefaultView()
        {
            poiListPanel.Visible = true;
            panelFilter.Visible = true;
            if (this.Controls.Contains(poiDetailPanel))
            {
                this.Controls.Remove(poiDetailPanel);
                poiDetailPanel.closePoiDetailPanel();
            }
            UpdatePanel();
        }

        /// <summary>
        /// Event method, occurs when the selected item in the ChronicComboBox changes.
        /// </summary>
        private void comboBoxChronic_SelectedIndexChanged(object sender, EventArgs e)
        {
            gui.pauseTimer();
            poiListPanel.Visible = false;
            panelFilter.Visible = false;
            if(this.Controls.Contains(poiDetailPanel))
                this.Controls.Remove(poiDetailPanel);

            addPoiDetailPanel((PoiDetail)comboBoxChronic.Items[comboBoxChronic.SelectedIndex]);
            PanelUpdated();
        }

        /// <summary>
        /// Event method, occurs when a default image of a POI arrived from server.
        /// </summary>
        private void serviceHandler_DefaultImageGot(Bitmap bitmap, string path)
        {
            poiListPanel.AddImage(path, bitmap);
        }

        /// <summary>
        /// Method to set the filter for an application on server site.
        /// </summary>
        public void SetFilter(Dictionary<string, bool> filter)
        {
            foreach (CatBox btn in panelFilter.Controls)
            {
                btn.UncheckFilter();

                if (filter.ContainsKey(btn.Name))
                    btn.CheckFilter();
            }

            serviceHandler.sendFilter(filter);
            dictFilter = filter;
        }

        /// <summary>
        /// Event method, occurs when the PoiDetail shown in the PoiPanel has completed update.
        /// </summary>
        private void serviceHandler_DetailUpdated(PoiDetail detail)
        {
            updatePoiDetailPanel(detail);
            PanelUpdated();
        }

        /// <summary>
        /// Method to set the max distance of shown pois on the client application.
        /// </summary>
        public void SetMaxDistance(string p)
        {
            serviceHandler.SetMaxDistance(p);
        }
    }
}
